/*
 *  objects-type.h
 *  joosVM
 *
 *  Created by Smári Waage on 6.9.2009.
 *  Copyright 2009 smari.org. All rights reserved.
 *
 *  This program is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU General Public License
 *  as published by the Free Software Foundation; either version 2
 *  of the License, or (at your option) any later version.
 *  
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *  
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. *
 */
#ifndef objects_type___ 
#define objects_type___ 

#include "objects-array.h"


/*
 * Field
 *
 * |	+HeapObject			|
 * +------------------------+
 * |	field name			|
 * +------------------------+
 * |	field type			|
 * +------------------------+
 * |		modifiers		|
 * +------------------------+
 * |	  position			|
 * +------------------------+
 */

class JField : public HeapObject {
protected:
	static const int kNameOffset = HeapObject::kHeaderSize;
	static const int kReturnTypeOffset = kNameOffset + kPointerSize;
	static const int kModifiersOffset = kReturnTypeOffset + kPointerSize;
	static const int kPositionOffset = kModifiersOffset + kPointerSize;
	
public:
	static const int kHeaderSize = kPositionOffset + kPointerSize;
	static JField* Initialize(){
		JField* f = (JField*)HeapObject::allocHeapObject(kHeaderSize);
		f->setInternalType(Smi::fromInt(IType_JField));		
		return f;
	}
	int fielddata_size(){ return kHeaderSize;}
	void fielddata_scan(Pointer** nHP){ 
		dout(debug_gc,"scan fielddata\n",0);
		setField(kNameOffset, getName()->forward(nHP));
		setField(kReturnTypeOffset, ((HeapObject*)getReturnType())->forward(nHP));
	}
	
	String* getName(){
		return (String*)field(kNameOffset);
	}
	
	void setName(String* name){	
		setField(kNameOffset, name);
	}
	
	Pointer* getReturnType(){
		return field(kReturnTypeOffset);
	}
	
	void setReturnType(Pointer* type){
		setField(kReturnTypeOffset, type);
	}
	
	void setModifiers(int modifiers){
		setField(kModifiersOffset, Smi::fromInt(modifiers));
	}
	int getModifier(){
		return ((Smi*)field(kModifiersOffset))->value();
	}
	void setPosition(int pos){
		setField(kPositionOffset,Smi::fromInt(pos));
	}
	int	getPosition(){
		return ((Smi*)field(kPositionOffset))->value();
	}
	
	bool isPrivate(){
		return (getModifier() & ACC_PRIVATE) == ACC_PRIVATE;
	}
	bool isPublic(){
		return (getModifier() & ACC_PUBLIC) == ACC_PUBLIC;
	}
	bool isProtected(){
		return (getModifier() & ACC_PROTECTED) == ACC_PROTECTED;
	}
	bool isStatic(){
		return (getModifier() & ACC_STATIC) == ACC_STATIC;
	}
	bool isFinal(){
		return (getModifier() & ACC_FINAL) == ACC_FINAL;
	}
	bool isVolatile(){
		return (getModifier() & ACC_VOLATILE) == ACC_VOLATILE;
	}
	bool isTransient(){
		return (getModifier() & ACC_TRANSIENT) == ACC_TRANSIENT;
	}
};

/*
 * Field
 *
 * |	+HeapObject			|
 * +------------------------+
 * |	field name			|
 * +------------------------+
 * |	field type			|
 * +------------------------+
 * |		modifiers		|
 * +------------------------+
 * |		value			|
 * +------------------------+
 */

class JStaticField : public JField {
	
	static const int kValueOffset = JField::kHeaderSize;
public:
	static const int kHeaderSize = kValueOffset + kPointerSize;
	
	static JStaticField* Initialize(){
		JStaticField* f = (JStaticField*)HeapObject::allocHeapObject(kHeaderSize);
		f->setInternalType(Smi::fromInt(IType_JStaticField));
		f->setValue(NULL);
		return f;
	}
	Pointer* getValue(){
		return field(kValueOffset);
	}
	void setValue(Pointer* value){
		setField(kValueOffset, value);
	}
	
	int staticfielddata_size(){ return JStaticField::kHeaderSize;}
	
	void staticfielddata_scan(Pointer** nHP){ 
		dout(debug_gc,"scan staticfielddata\n",0);
		setField(kNameOffset, getName()->forward(nHP));
		setField(kReturnTypeOffset, ((HeapObject*)getReturnType())->forward(nHP));
		Pointer* v = getValue();
		if(v != NULL){
			char c = ((String*)getReturnType())->str()[0];
			if(c == 'L' || c == '[' || c == 'D' || c == 'J'){
				setField(kValueOffset, ((HeapObject*)v)->forward(nHP));
			}
		}
	}
};

/*
 * AbstractMethod
 *
 * |	+JField			|
 * +------------------------+
 * |	method parameters	|
 * +------------------------+
 * |		JType		|
 * +------------------------+
 */
class JAbstractMethod : public JField {
protected:
	static const int kMethodParameters = JField::kHeaderSize;
	static const int kContainingTypeOffset = kMethodParameters + kPointerSize;
public:
	static const int kHeaderSize = kContainingTypeOffset + kPointerSize;
	
	bool isSynchronized(){
		return (getModifier() & ACC_SYNCHRONIZED) == ACC_SYNCHRONIZED;
	}
	bool isNative(){
		return (getModifier() & ACC_NATIVE) == ACC_NATIVE;
	}
	bool isAbstact(){
		return (getModifier() & ACC_ABSTRACT) == ACC_ABSTRACT;
	}
	
	StaticArray* getMethodParameters(){
		return (StaticArray*)field(kMethodParameters);
	}
	void setMethodParameters(StaticArray* para){
		setField(kMethodParameters, para);
	}
	JType* getContainingType(){
		return (JType*)field(kContainingTypeOffset);
	}
	void setContainingType(HeapObject* type){
		setField(kContainingTypeOffset, type);
	}
	
	int abstractmethoddata_size(){ return JAbstractMethod::kHeaderSize;}
	void abstractmethoddata_scan(Pointer** nHP){ 
		dout(debug_gc,"scan abstractmethoddata\n",0);
		setField(kNameOffset, getName()->forward(nHP));
		setField(kReturnTypeOffset, ((HeapObject*)getReturnType())->forward(nHP));
		
		setField(kMethodParameters, getMethodParameters()->forward(nHP));
										//forward declaration problem.
		setField(kContainingTypeOffset, ((HeapObject*)getContainingType())->forward(nHP));
	}
};


#if TRACE_JIT

//To hold a tracetree and information related to it.
class TraceTreeObject : public HeapObject {
	
	static const int kFragmentOffset = HeapObject::kHeaderSize;
	static const int kStartPcOffset = kFragmentOffset + kPointerSize;
	static const int kEndPcOffset = kStartPcOffset + kPointerSize;
	static const int kCallSizeOffset = kEndPcOffset + kPointerSize;
	static const int kVTableOffset = kCallSizeOffset + kPointerSize;
	static const int kStateOffset = kVTableOffset + kPointerSize;
public:
	static const int kHeaderSize = kStateOffset + kPointerSize;
	
	static TraceTreeObject* Initialize(){
		TraceTreeObject* t = (TraceTreeObject*) HeapObject::allocHeapObject(TraceTreeObject::kHeaderSize);
		t->setInternalType(Smi::fromInt(IType_TraceTreeObject));	
		t->setVTable(StaticArray::Initalize(2));
		return t;
	}
	
	Fragment* getFragment(){ return (Fragment*)field(kFragmentOffset);}
	void setFragment(Fragment* fragment){ setField(kFragmentOffset,(Pointer*)fragment);}
	
	int getStartPc(){ return ((Smi*)field(kStartPcOffset))->value();}
	void setStartPc(int startpc){ setField(kStartPcOffset,Smi::fromInt(startpc));}
	
	int getEndPc(){ return ((Smi*)field(kEndPcOffset))->value();}
	void setEndPc(int endpc){ setField(kEndPcOffset,Smi::fromInt(endpc));}
	
	int getCallSize(){ return ((Smi*)field(kCallSizeOffset))->value();}
	void setCallSize(int callsize){ setField(kCallSizeOffset,Smi::fromInt(callsize));}
	
	RecordState getState(){ return (RecordState)((Smi*)field(kStateOffset))->value();}
	void setState(RecordState state){ setField(kStateOffset,Smi::fromInt(state));}
	
	StaticArray* getVTable() { return (StaticArray*)field(kVTableOffset);}
	void setVTable(StaticArray* vtable){ setField(kVTableOffset, vtable);}
	
	int tracetreeobject_size(){ return TraceTreeObject::kHeaderSize;}
	
	void tracetreeobject_scan(Pointer** nHP){
		//only need to fw vtable, 
		//need to take care of what is written in there because of garbage collection(retain)
		setField(kVTableOffset, getVTable()->forward(nHP));
		//then I need to update the fragment->vmprivate with new this info.
		getFragment()->vmprivate = this; 
	}
	
};

#endif

/*
 * Method
 *
 * |	+JAbstractMethod	|
 * +------------------------+
 * |		MaxStackSize	|
 * +------------------------+
 * |		MaxLocals		|
 * +------------------------+
 * |		code			| bytearray
 * +------------------------+
 * |	exceptionTable		| 
 * +------------------------+
 */
class JMethod : public JAbstractMethod {
protected:
	static const int kMaxStackSizeOffset = JAbstractMethod::kHeaderSize;
	static const int kMaxLocals = kMaxStackSizeOffset + kPointerSize;
	static const int kCodeOffset = kMaxLocals + kPointerSize;
	static const int kExceptionTable = kCodeOffset + kPointerSize;

	
#if TRACE_JIT	
	static const int kTraceCountOffset = kExceptionTable + kPointerSize;
	static const int kFragmentPointersOffset = kTraceCountOffset + kPointerSize;
public:
	static const int kHeaderSize = kFragmentPointersOffset + kPointerSize;
#else
public:
	static const int kHeaderSize = kExceptionTable + kPointerSize;
#endif
	
	static JMethod* Initialize(){
		JMethod* m = (JMethod*)HeapObject::allocHeapObject(kHeaderSize);
		m->setInternalType(Smi::fromInt(IType_JMethod));
		//TODO: fix this hack
		m->setField(kCodeOffset, NULL);
		return m;
	}
	
	int getMaxStackSize(){ return ((Smi*)field(kMaxStackSizeOffset))->value();}
	void setMaxStackSize(int max){ setField(kMaxStackSizeOffset,Smi::fromInt(max));}
	
	int getMaxLocals(){ return ((Smi*)field(kMaxLocals))->value();}
	void setMaxLocals(int max){ setField(kMaxLocals, Smi::fromInt(max));}
	
	ByteArray* getCode(){ return (ByteArray*)field(kCodeOffset);}

	void setCode(ByteArray* code){ 
		setField(kCodeOffset, code);
		
#if not TRACE_JIT
	}	
#else /*Note extending the method*/
	
		//start with stubit and slow, this is a one time affair when the code is set.
		ByteArray* tc = ByteArray::Initialize(code->array_length());
		tc->clear();
		setField(kTraceCountOffset,tc);
		setField(kFragmentPointersOffset,NULL);
	}

	// shoot me!!, just a temporary solution untill I make a random, store in a seperate list etc...
	static const int kTraceIndexStart = 30;
	void setFragmentRecorderIndex(int index, int idx){
		ByteArray* tc = (ByteArray*) field(kTraceCountOffset);
		tc->set(index,idx+kTraceIndexStart);
	}
	
	Pointer* getFragmentRecorder(int idx){
		StaticArray* a = (StaticArray*)field(kFragmentPointersOffset);
		if(a == NULL || a->array_length() <= idx) return NULL;
		else {
			return a->get(idx);
		}
	}
	int setFragmentRecorder(Pointer* f, int index){
		StaticArray* a = (StaticArray*)field(kFragmentPointersOffset);
		if(a == NULL){ 
			a = StaticArray::Initalize(2);
			a->set(0,f);
			setField(kFragmentPointersOffset,a);
			setFragmentRecorderIndex(index,0);
			return 0;
		}else{
			int l = a->array_length();
			int i = 1;
			while(i<l){
				if(a->get(i) == NULL){
					//find a vacancy and break the loop
					a->set(i, f);
					setFragmentRecorderIndex(index,i);
					return i;
				}
				i++;
			}
			//if I reach here I need to extend the array
			StaticArray* na = StaticArray::Initalize(l*2);//not an optimal growth
			i = 0;
			while(i<l){
				na->set(i,a->get(i));
				i++;
			}
			na->set(i,f);
			setField(kFragmentPointersOffset,na);
			setFragmentRecorderIndex(index,i);
			return i;
		}
	}
	void blacklist(int index){
		ByteArray* tc = (ByteArray*) field(kTraceCountOffset);
		tc->set(index,0xFF);
	}
	bool checkLoopHead(int index){
		ByteArray* tc = (ByteArray*) field(kTraceCountOffset);
		return index < tc->array_length() && tc->get(index) >= kTraceIndexStart;
	}

	TraceTreeObject* backJump(int index){
		//todo: move
		static const int kTraceThreshold = 10;
		
		//lets make some return states
		// 0 = not hit any threashold, or ignore
		// 1 = first time;
		// 2 = second time;
		// 3 = 
		// 4 = 
		
		//array states
		// 0 - 20 = count
		// 0xFF/255 = dont touch finished with it, blacklist
		// 30 <  x < 0xFF index of the fragment.
		ByteArray* tc = (ByteArray*) field(kTraceCountOffset);
		int i = tc->get(index);
		if(i == 0xFF){
			return NULL;
		}else if(i < kTraceThreshold){
			tc->set(index, ++i);
			return NULL;
		}else if(i==kTraceThreshold){
			return (TraceTreeObject*)1;
		}else{
			TraceTreeObject* tto = (TraceTreeObject*)getFragmentRecorder(i-kTraceIndexStart);
			if(tto->getState() == BlackList){
				tc->set(index,0xFF);
				return NULL;
			}
			return tto;
		}			
	}
#endif 

	HashTable* getExceptionTable(){
		return (HashTable*) field(kExceptionTable);
	}
	void setExceptionTable(HashTable* table){
		setField(kExceptionTable, table);
	}

	

	void invokeNative(TaggedArray* locals, Stack* s){
		native_func n;
		n.pointer = getCode();
		if(!n.pointer){
			n = NativeMethods::linkMethod(this);
			if(n.pointer){
				setField(kCodeOffset,n.pointer);
			}else{
				//todo:exception linking error.
				printf("Bad native call!!");exit(1);
			}
		}
		n.func(locals,s);
		
		//NativeMethods::callNativeMethod(this,locals,s);
	}

	

	int methoddata_size(){ return JMethod::kHeaderSize;}
	
	void methoddata_scan(Pointer** nHP){ 
		dout(debug_gc,"scan methoddata\n",0);
		setField(kNameOffset, getName()->forward(nHP));
		setField(kReturnTypeOffset, ((HeapObject*)getReturnType())->forward(nHP));
		
		setField(kMethodParameters, getMethodParameters()->forward(nHP));
		//forward declaration problem.
		setField(kContainingTypeOffset, ((HeapObject*)getContainingType())->forward(nHP));
		
		if((getModifier()&ACC_NATIVE) != ACC_NATIVE)
			setField(kCodeOffset, getCode()->forward(nHP));
#if TRACE_JIT
		setField(kTraceCountOffset, ((HeapObject*)field(kTraceCountOffset))->forward(nHP));
		HeapObject* frags = ((HeapObject*)field(kFragmentPointersOffset));
		if(frags != NULL)
			setField(kFragmentPointersOffset,frags->forward(nHP));
#endif
	}
	
};


/*
 * class
 *
 * |	+HeapObject			|
 * +------------------------+
 * |		name			|
 * +------------------------+
 * |		super			|
 * +---------+--------------+
 * |	type | modifiers	|
 * +---------+--------------+
 * |	Interface list		|
 * +------------------------+
 * |	constant pool		|
 * +------------------------+
 * |	field array			|
 * +------------------------+
 * |	method array		|
 * +------------------------+
 * |	static vars			|
 * +------------------------+
 * |	class loader		|
 * +------------------------+
 * |	class ref			|
 * +------------------------+
 */

class JType : public HeapObject {
	
	static const int kNameOffset = HeapObject::kHeaderSize;
	static const int kSuperOffset = kNameOffset + kPointerSize;
	static const int kType_ModifiersOffset = kSuperOffset + kPointerSize;
	static const int kInterfacesOffset = kType_ModifiersOffset + kPointerSize;
	static const int kConstantPoolOffset = kInterfacesOffset + kPointerSize;
	static const int kFieldsOffset = kConstantPoolOffset + kPointerSize;
	static const int kMethodsOffset = kFieldsOffset + kPointerSize;
	static const int kStaticVarsOffset = kMethodsOffset + kPointerSize;
	static const int kClassLoaderOffset = kStaticVarsOffset + kPointerSize;
	static const int kClassRefOffset = kClassLoaderOffset + kPointerSize;
	
public:
	static const int kHeaderSize = kClassRefOffset + kPointerSize;
	
	static JType* Initialize(){
		JType* t = (JType*) HeapObject::allocHeapObject(JType::kHeaderSize);
		t->setInternalType(Smi::fromInt(IType_JType));		
		return t;
	}
	
	String* getName(){ return (String*)field(kNameOffset);}
	void setName(String* name){ setField(kNameOffset, name);}
	
	
	int getType(){ return (int)field(kType_ModifiersOffset) >> 16;}
	int getModifiers(){	return ((int)field(kType_ModifiersOffset)) & 0x0F;}
	
	void setType(int type){setField(kType_ModifiersOffset, (Pointer*)((type << 16) & getModifiers()));}
	void setModifiers(int modifiers){ setField(kType_ModifiersOffset, (Pointer*)((getType() << 16) & modifiers));}
	
	bool isPublic(){ return (getModifiers() & ACC_PUBLIC) == ACC_PUBLIC;}
	bool isPrivate(){ return (getModifiers() & ACC_PRIVATE) == ACC_PRIVATE;}
	bool isAbstact(){ return (getModifiers() & ACC_ABSTRACT) == ACC_ABSTRACT;}
	
	StaticArray* getInterfaces(){ return (StaticArray*)field(kInterfacesOffset);}
	void setInterfaces(StaticArray* interfaces){ setField(kInterfacesOffset, interfaces);}
	
	StaticArray* getConstantPool(){ return (StaticArray*)field(kConstantPoolOffset);}
	void setConstantPool(StaticArray* constantpool){ setField(kConstantPoolOffset, constantpool);}
	
	JType* getSuper(){ 
		JType* _super = (JType*)field(kSuperOffset);
		/*
		if(_super->isSmi() && _super != 0){
			int super_name_index = ((Smi*)getConstantPool()->get(((Smi*)_super)->value() - 1))->value();
			String* super_name = (String*)getConstantPool()->get(super_name_index -1);
			//if(!strcmp(super_name->str(), "java/lang/Object"))
			//	s = 0;
			//else
			
			//oops I cant reach the class loader.
			_super = (JType*)((HashTable*)Heap::getMethodArea())->lookup(super_name);
		}*/
		return _super;
	}
	void setSuper(JType* sup){ setField(kSuperOffset, sup);}
	//Todo: super
	
	
	HashTable* getFields(){ return (HashTable*)field(kFieldsOffset);}
	void setFields(HashTable* fields){ setField(kFieldsOffset, fields);}
	
	HashTable* getMethods(){ return (HashTable*)field(kMethodsOffset);}
	void setMethods(HashTable* methods){ setField(kMethodsOffset, methods);}
	
	HashTable* getStaticVars(){ return (HashTable*)field(kStaticVarsOffset);}
	void setStaticVars(HashTable* staticvars){ setField(kStaticVarsOffset, staticvars);}
	
	JType* getClassLoader(){ return (JType*)field(kClassLoaderOffset);}
	void setClassLoader(JType* classloader){ setField(kClassLoaderOffset, classloader);}
	
	JMethod* lookupMethod(String* name){
		return (JMethod*)getMethods()->lookup(name);
	}
	
	JField* getField(String* name){
		return (JField*)getFields()->lookup(name);
	}
	
	
	
	JType* lookupAndLinkType(int index){
		StaticArray* constpool = getConstantPool();
		JType* class_info = (JType*)constpool->get(index-1);
		if(class_info->isHeapObject()){
			return class_info;
		}else{
			String* class_name = ((String*)constpool->get(((Smi*)class_info)->value() -1));
			JType* returnType = ClassLoader::findType(class_name);
			if(returnType == NULL){throwException("java/lang/UnsatisfiedLinkError");}
			constpool->set(index-1, returnType);
			return returnType;
		}
	}
	
	JType* lookupAndLinkSuper(JType* son){
		Pointer* tmp = son->getSuper();
		if(tmp->isSmi()){
			int index = ((Smi*)tmp)->value();
			if(index == 0)
				return NULL;
			else{
				JType* zuper = son->lookupAndLinkType(index);
				son->setSuper(zuper);
				return zuper;
			}
		}else{
			return(JType*)tmp;
		}
	}	
	
	JMethod* lookupAndLinkMethod(int index){
		StaticArray* constpool = getConstantPool();
		JMethod* returnMethod;
		Pointer* methodInfo = constpool->get(index-1);
		if(methodInfo->isSmi()){
			int met_info = ((Smi*)methodInfo)->value();
			//constant name and type
			int name_and_type = ((Smi*)constpool->get((met_info>> 8) -1))->value();
			String* met = (String*)constpool->get((name_and_type & 0xFF)-1);
			String* sig = (String*)constpool->get((name_and_type >>8)-1); 
			
			const char* cname = met->str();
			const char* creturntype = sig->str();
						
			String* signature = String::Initialize(strlen(cname) + strlen(creturntype) + 1);
			signature->setStr(cname);
			signature->insertStr(creturntype, strlen(cname));
			
			JType* returnType = lookupAndLinkType( (0xFF & met_info));
			
			//free(ig);
			while((returnMethod = returnType->lookupMethod(signature)) == NULL ){
				//we have reached the top we cant find the method.
				if(!strcmp(returnType->getName()->str(),"java/lang/Object")){throwException("java/lang/UnsatisfiedLinkError");}
				//look up the hierachy
				returnType = lookupAndLinkSuper(returnType);
				
			}
			constpool->set(index-1,returnMethod);
		}else{
			returnMethod = (JMethod*)methodInfo;
		}
		return returnMethod;
	}
	
	JStaticField* getStaticFieldWithIndex(int index){
		
		StaticArray* constpool = getConstantPool();
		JField* field_ref  = (JField*)constpool->get(index-1);
		
		if(field_ref->isSmi()){		
			int field_ref_info = ((Smi*)field_ref)->value();	
			int class_index = 0xFF & field_ref_info;//constant class info
			JType* returnType = lookupAndLinkType(class_index);
			
			int name_and_type_index = field_ref_info>> 8;//constant name and type
			int nt = ((Smi*)constpool->get(name_and_type_index-1))->value();
			String* _name = (String*)constpool->get((nt & 0xFF)-1);
			field_ref = (JStaticField*)returnType->getField(_name);
			
			if(field_ref->isPrivate()){
				if(this != returnType)
					throwException("java/lang/IllegalAccessError");
			}else if(field_ref->isProtected()){
				JType* tmptype = this;
				bool found = false;
				do{
					if(tmptype == returnType)
						found = true;
				}while((tmptype = lookupAndLinkSuper(tmptype))!= NULL && !found);
				if(!found)
					throwException("java/lang/IllegalAccessError");
			}
		}
		
		//JStaticField* field_ref  = (JStaticField*)getFieldWithIndex(constpool, index);
		if(!field_ref->isStatic()){throwException("java/lang/IncompatibleClassChangeError");}
		
		return (JStaticField*)field_ref;
	}
	
	
	
	
	
	
	
		
	int typedata_size(){ return JType::kHeaderSize;}
	
	void typedata_scan(Pointer** nHP){
		dout(debug_gc,"scan typedata\n",0);
		setField(kNameOffset,getName()->forward(nHP));
		setField(kSuperOffset,((HeapObject*)field(kSuperOffset))->forward(nHP));
		//setField(kInterfacesOffset,getInterfaces()->forward(nHP));
		setField(kConstantPoolOffset,getConstantPool()->forward(nHP));
		setField(kFieldsOffset,getFields()->forward(nHP));
		setField(kMethodsOffset,getMethods()->forward(nHP));
		setField(kStaticVarsOffset,getStaticVars()->forward(nHP));
		setField(kClassLoaderOffset,getClassLoader()->forward(nHP));
	}
};

/*
 * Instance
 *
 * |	+HeapObject			|
 * +------------------------+
 * |		type			| 
 * +------------------------+
 * |		values			| 
 * +------------------------+
 */

class Instance : public HeapObject{
	
	static const int kTypeOffset = HeapObject::kHeaderSize;
	static const int kValuesOffset = kHeaderSize + kPointerSize;
public:
	static const int kHeaderSize = kValuesOffset + kPointerSize;
	
	static Instance* Initialize(JType* type){
		Instance* obj = (Instance*) HeapObject::allocHeapObject(kHeaderSize);
		obj->setInternalType(Smi::fromInt(IType_Instance));
		obj->setField(kTypeOffset, type);
		obj->setValues(HashTable::Initialize(type->getFields()->capacity()));
		return obj;
	}
	
	JType* getType(){
		return (JType*)field(kTypeOffset);
	}
	void setType(JType* type){
		setField(kTypeOffset, type);
	}
	
	HashTable* getValues(){
		return (HashTable*)field(kValuesOffset);
	}
	void setValues(HashTable* values){
		setField(kValuesOffset, values);
	}
	
	Pointer* getField(int index){
		
		StaticArray* constpool = getType()->getConstantPool();
		
		int field_ref_info = ((Smi*)constpool->get(index-1))->value();
		
		//int class_index = 0xFF & field_ref_info;//constant class info
		//Smi* name_index = (Smi*)constpool->get(class_index-1);
		//String* class_name = (String*)constpool->get(name_index->value()-1);
		
		int name_and_type_index = field_ref_info>> 8;//constant name and type
		Smi* name_and_type = (Smi*)constpool->get(name_and_type_index-1);
		
		int nt = name_and_type->value();
		String* _name = (String*)constpool->get((nt & 0xFF)-1);
		
		//String* _type = (String*)constpool->get((nt >>8)-1);
		Pointer* v = getValues()->lookup(_name);
		if(v == NULL)
			return NULL;
		else
			return ((TaggedValue*)v)->getValue();
	}
	
	void putField(int index, Pointer* value){
		StaticArray* constpool = getType()->getConstantPool();
		int field_ref_info = ((Smi*)constpool->get(index-1))->value();
		
		//int class_index = 0xFF & field_ref_info;//constant class info
		//Smi* name_index = (Smi*)constpool->get(class_index-1);
		//String* class_name = (String*)constpool->get(name_index->value()-1);
		
		int name_and_type_index = field_ref_info>> 8;//constant name and type
		Smi* name_and_type = (Smi*)constpool->get(name_and_type_index-1);
		
		int nt = name_and_type->value();
		String* _name = (String*)constpool->get((nt & 0xFF)-1);
		TaggedValue* v = (TaggedValue*)getValues()->lookup(_name);
		if(v == NULL){
			String* _type = (String*)constpool->get((nt >>8)-1);
			char c = _type->str()[0];
			getValues()->set(_name,TaggedValue::Initalize(value, (c == 'L' || c == '[')));
		}else{
			v->setValue(value);
		}
	}
	
	int instance_size(){ return Instance::kHeaderSize;}
	void instance_scan(Pointer** nHP){
		dout(debug_gc,"scan instance\n",0);
		setField(kTypeOffset,getType()->forward(nHP));
		setField(kValuesOffset,getValues()->forward(nHP));
	}
	
};

#endif
